import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

class TweetsFetcher extends Thread {
	Client client;

	// Use this object to notify workers that there are jobs to do
	public Object hasJob = new Object();
	
	int workingKids = 0;
	
	int runningKids = 0;
	
	int currentPage = -1;
	
	int stoppingKids = 0;
	
	int failed = 0;
		
	// boolean gotUserInformation = false;

	public TweetsFetcher(Client client) {
		this.client = client;
	}
	
	synchronized public void startNewPageFetcher() {
		// System.err.println("started");
		PageFetcher kid = new PageFetcher(this);
		kid.start();
		runningKids++;
	}
	
	private void startDefaultNrOfPageFetchers() {
		for(int i = 0; i < client.getMaxPageFetcherThreads(); i++) {
			startNewPageFetcher();
		}
	}
	
	public void tryToStartPageFetchers() {
		for(int i = 0; runningKids < client.getMaxPageFetcherThreads(); i++) {
			startNewPageFetcher();
		}
	}
	
	synchronized public void increaseStoppingKids() {
		if(runningKids - stoppingKids <= 0) {
			return;
		}
		stoppingKids++;
	}
	
	synchronized public void decreaseStoppingKids() {
		if(stoppingKids == 0) {
			return;
		}

		stoppingKids--;
	}
	
	synchronized public boolean shouldKillSomeKids() {
		if(stoppingKids > 0) {
			System.err.println(stoppingKids);

			decreaseStoppingKids();
			return true;
		}
		
		return false;
	}
	
	@Override
	public void run() {
		// Start all page fetchers thread
		startDefaultNrOfPageFetchers();
		
		while(true) {
			synchronized(this) {
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

			synchronized(hasJob) {
				System.out.println(" + Fetching pages");
				resetPageNumber();
				hasJob.notifyAll();
			}
		}
	}
	
	synchronized public boolean hasPageToLoad() {
		return currentPage >= 0;
	}

	synchronized public URL getPageURL() {
		URL url = null;

		// We tell pagefetcher that there are no more page to fetch
		if(!hasPageToLoad()) {
			return url;
		}
		
		++currentPage;
		try {
			String sinceParam = "";
			if(client.user.lastTwitt != null) {
				sinceParam = "&since_id="+client.user.lastTwitt;
			}
			url = new URL("http://api.twitter.com/1/statuses/user_timeline.xml?user_id="+ client.user.id + sinceParam +"&count=50&page="+ currentPage);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		return url;
	}
	
	synchronized private void resetPageNumber() {
		currentPage = 0;
	}

	synchronized public void handlePageResults(String xml) {
		if(xml == null) {
			failed++;
			if(failed >= 5) {
				client.stopClient("Client was blocked by Twitter");
				failed = 0;
				return;
			}
		}
		else {
			failed = 0;
		}
		
		Twitt[] tweets = parse(xml);
		if(tweets.length > 0) {
			client.handleTweetResults(tweets);
			
			// Stop loading next pages user has stoped the client
			if(!client.isRunning()) {
				currentPage = -1;
			}
		}
		else {
			currentPage = -1;
		}
		
		// Enable this line to fetch only a few tweets pro user
		// System.err.println("Client will fetch as least tweets as posible (TweetsFetcher.java > handlePageResults())");
		currentPage = -1;
	}

	synchronized public void increaseWorkingKids() {
		workingKids++;
	}
	
	synchronized public void decreaseWorkingKids() {
		workingKids--;
		// Tell client that job is done
		if(allKidsAreDone()) {
			client.hasDoneFetchingTweets();
		}
	}
	
	private boolean allKidsAreDone() {
		return workingKids <= 0;
	}
	
	private Twitt[] parse(String xml) {
		if(xml == null) {
			return new Twitt[0];
		}
		NodeList ids = Helper.parseXMLWithXPath(xml, "//status");
		Twitt[] tweets = new Twitt[ids.getLength()];
		for(int i = 0; i < ids.getLength(); i++) {
			NodeList tweetData	= ids.item(i).getChildNodes();

			String created_at = null;
			String id = null;
			String text = null;
			String source = null;
			String place = null;
			for(int j = 0; j < tweetData.getLength(); j++) {
				Node currentChild = tweetData.item(j);
				String nodeName = currentChild.getNodeName();
				if(nodeName.equals("created_at")) {
					created_at = currentChild.getTextContent();
					created_at = convertDateAndTime(created_at);
				}
				else if(nodeName.equals("id")) {
					 id = currentChild.getTextContent();
				}
				else if(nodeName.equals("text")) {
					 text = currentChild.getTextContent();
				}
				else if(nodeName.equals("source")) {
					 source = currentChild.getTextContent();
				}
				else if(nodeName.equals("place")) {
					 place = currentChild.getTextContent();
				}
				/*else if(nodeName.equals("user") && !gotUserInformation) {
					NodeList userData = currentChild.getChildNodes();
					HashMap<String, String> data = new HashMap<String, String>();
					for(int k = 0; k < userData.getLength(); k++) {
						currentChild = userData.item(k);
						nodeName = currentChild.getNodeName();
						if(nodeName.equals("name")) {
							data.put("name", currentChild.getTextContent());
						}
						else if(nodeName.equals("screen_name")) {
							data.put("screen_name", currentChild.getTextContent());
						}
						else if(nodeName.equals("location")) {
							data.put("location", currentChild.getTextContent());
						}
						else if(nodeName.equals("url")) {
							data.put("url", currentChild.getTextContent());
						}
						else if(nodeName.equals("description")) {
							data.put("description", currentChild.getTextContent());
						}
					}
					
					client.handleUserDataResults(data);
					gotUserInformation = true;
				}*/
			}

			Twitt tweet = new Twitt(id, text, created_at, source, place);
			tweets[i] = tweet;
		}
		return tweets;
	}
	
	private String convertDateAndTime(String date) {
		String[] dates = date.split(" ");

		String month = dates[1];
		String day = dates[2];
		String time = dates[3];
		String year = dates[5];
		
		if(Integer.parseInt(day) <= 9) {
			day = "0"+day;
		}
		day = day.replaceAll("00", "0");
		
		HashMap<String, String> months = new HashMap<String, String>(12);
		months.put("Jan","01");
		months.put("Feb","02");
		months.put("Mar","03");
		months.put("Apr","04");
		months.put("May","05");
		months.put("Jun","06");
		months.put("Jul","07");
		months.put("Aug","08");
		months.put("Sep","09");
		months.put("Oct","10");
		months.put("Nov","11");
		months.put("Dec","12");
		
		String dateString = year+"-"+months.get(month)+"-"+day+" "+time;
		
		return dateString;
	}
}
